package com.lixinlei.security.auth.oauth2.config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
//import org.springframework.session.jdbc.config.annotation.web.http.EnableJdbcHttpSession;

/**
 * 对认证服务器的配置要包括：
 * 1.哪些客户端应用会访问我
 * 2.哪些用户是合法用户
 * 3.谁能找我验证这个令牌
 */
//@EnableJdbcHttpSession
@Configuration
@EnableAuthorizationServer // 当前应用是作为认证授权服务器存在的
public class OAuth2AuthServerConfig extends AuthorizationServerConfigurerAdapter {

    /**
     * 用来告诉认证服务器，合法的用户有哪些
     * 在 {@link OAuth2WebSecurityConfig#authenticationManagerBean()} 中暴露出来的 Bean
     */
    @Autowired
    private AuthenticationManager authenticationManager;

    /**
     * 在 {@link OAuth2WebSecurityConfig#passwordEncoder()} 中暴露出来的 Bean
     */
    @Autowired
    private PasswordEncoder passwordEncoder;

    /**
     * 自己的实现，合法用户的来源：{@link UserDetailsServiceImpl}
     */
    @Autowired
    private UserDetailsService userDetailsService;

//    @Autowired
//    private DataSource dataSource;

//    @Bean
//    public TokenStore tokenStore() {
//        return new JdbcTokenStore(dataSource);
//    }

    /**
     * 1. 哪些客户端应用会访问我（认证服务）
     * @param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//        clients.jdbc(dataSource);
        clients.inMemory()
                .withClient("orderApp") // 可以让哪个客户端应用访问我这个认证服服务
                .secret(passwordEncoder.encode("123456")) // 客户端应用的密码
                .scopes("read", "write") // 将应用 orderApp 与它的权限挂钩，相当于 ACL，意思是 orderApp 拿着这个 Token 访问 order-server 能干什么
                .accessTokenValiditySeconds(3600) // 发出去的 Token 的有效期，单位：s
                .resourceIds("order-server") // 发出去的 Token 可以访问哪些资源服务器
                .authorizedGrantTypes("password") // OAuth2 有四种授权方式：password

                .and()

                // 配置一个资源服务器
                .withClient("orderService")
                .secret(passwordEncoder.encode("123456"))
                .scopes("read")
                .accessTokenValiditySeconds(3600)
                .resourceIds("order-server")
                .authorizedGrantTypes("password");

    }

    /**
     * 2. 哪些用户是合法用户
     * @param endpoints
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.authenticationManager(authenticationManager);
    }


    /**
     * 3. 谁能找我验证这个令牌
     * @param security
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        // 填了一个权限表达式，意思是来验 Token 的请求一定是通过身份认证的，就是要带着用户名密码，
        // 要么是 orderApp:123456，要么是 orderService:123456
        security.checkTokenAccess("isAuthenticated()");
    }

}
